/*
 * song definitions
 *
 * Choi Jonghwan <saxboy@gmail.com>
 * 2006/04/22
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "song.h"

BAR bar_New(void)
{
	BAR b=NULL; 
	b = (BAR)malloc(sizeof(_BAR)); 
	if ( b==NULL) return NULL; 

	memset(b, 0, sizeof(_BAR)); 
	return b; 
}
int bar_Delete(BAR b)
{
	if (b==NULL) return -1; 

	{
		int i=0; 

		for (i=0; i< b->chord_count; i++)
			chord_Delete( b->chords[i].chord); 
	}

	free(b); 
	return 1; 
}

int bar_SetMeasure(BAR b, int count, int base)
{
	if (b==NULL) return -1; 
	b->measure_count = count; 
	b->measure_base = base; 
	return 1; 
}

int bar_AddChord(BAR b, CHORD c, int beat)
{
	if (b==NULL) return -1; 

	b->chords[ b->chord_count ].chord = c; 
	b->chords[ b->chord_count ].beat_length = beat; 
	b->chord_count++; 
	
	return 1; 
}

int bar_SetChord(BAR b, CHORD c, int beat, int b_same_as_prev)
{
	if (b==NULL) return -1; 
	/* chord c can be null here */

	//printf("setchord beat=%d, same_prev=%d\n", beat, b_same_as_prev); 

	if (b->chords[beat].chord !=NULL)
		chord_Delete( b->chords[beat].chord); 

	b->chords[beat].chord = c; 
	b->chords[beat].b_same_as_prev_chord = b_same_as_prev; 

	b->chord_count++; 

	return 1; 
}

int bar_GetChordCount(BAR b)
{
	if (b==NULL) return -1; 
	return b->chord_count; 
}

CHORD bar_GetChord(BAR b, int beat)
{
	if (b==NULL) return NULL; 

	{
		CHORD c=NULL; 

		c = b->chords[beat].chord; 
		if ( c==NULL )
		{
			if ( beat < 1) goto error; 

			if ( b->chords[beat].b_same_as_prev_chord )
				c = b->chords[beat-1].chord; 
		}

		return c; 
	}

error:
	printf("b=0x%x, beat=%d, chord=NULL\n", b, beat); 
	return NULL; 
}


int bar_ImportString(BAR b, const char *str)
{
	if (b==NULL) return -1; 
	if (str==NULL) return -1; 
	if (str[0]=='\0') return -1; 
	//if (b->measure_count<1) return -1; 
	//if (b->measure_base<1) return -1; 

	/* FIXME: what can i do if there's no measure yet */

	{
		char *tok=NULL; 
		CHORD c=NULL; 
		int beat=0; 
		char tmp[128]={0,}; 

		strncpy(tmp, str, 128); 
		tok = strtok( tmp, " "); 
		while ( tok!=NULL)
		{
			//printf("-- tok=[%s]\n", tok); 

			if ( tok[0]=='-') 
			{
				bar_SetChord(b, NULL, beat, 1); 
			}
			else
			{
				if ( (c = chord_NewFromString(tok) )==NULL )
				{
					printf("failed to import chord to bar (%s)\n", tok); 
					return -1; 
				}

				bar_SetChord(b, c, beat, 0); 
			}

			beat++; 
			tok = strtok(NULL, " "); 
		}
	}

	return 1; 	
}

BAR bar_NewFromString(const char *barstr)
{
	BAR b=NULL; 
	b = bar_New(); 
	if ( b!=NULL)
	{
		if ( bar_ImportString(b, barstr) < 0 )
			goto error; 
	}
	return b; 

error:
	bar_Delete(b); 
	return NULL; 
}

SONG song_New(void)
{
	SONG s=NULL; 
	s = (SONG)malloc(sizeof(_SONG)); 
	if ( s==NULL) return NULL; 
	memset(s, 0, sizeof(_SONG)); 
	return s; 
}

int song_Delete(SONG s)
{
	if (s==NULL) return -1; 

	{
		int i=0; 

		for (i=0; i< s->bar_count; i++)
			bar_Delete( s->bars[i]); 

		for (i=0; i< s->voice_count; i++)
			voice_Delete( s->voices[i]); 
	}

	free(s); 
	return 1; 
}

int song_SetMeasure(SONG s, int count, int base)
{
	if (s==NULL) return -1; 
	s->measure_count = count; 
	s->measure_base = base; 
	return 1; 
}

int song_AddBar(SONG s, BAR b)
{
	if (s==NULL) return -1; 
	if (b==NULL) return -1; 

	if (b->measure_count == 0 )
		b->measure_count = s->measure_count; 
	if (b->measure_base == 0 )
		b->measure_base = s->measure_base; 

	s->bars[ s->bar_count ] = b; 
	s->bar_count++; 

	return 1; 
}

int song_Print(SONG s, FILE *fp)
{
	int i=0; 

	if (s==NULL) return -1; 
	if (fp==NULL) return -1; 

	for (i=0; i<s->bar_count; i++)
	{
		int chord_idx=0; 
		BAR b = s->bars[i]; 

		if ( b==NULL) continue; 

		//if ( i%4 == 0 ) fprintf(fp, "\n"); 
		fprintf(fp, "BAR %d :  ", i ); 
		for (chord_idx=0; chord_idx < b->measure_count; chord_idx++)
		{
			if ( b->chords[chord_idx].chord==NULL ) 
			{
				if ( b->chords[chord_idx].b_same_as_prev_chord )
					fprintf(fp, "%6s", " - "); 
			}
			else
				fprintf(fp, "%6s", chord_GetStaticString(b->chords[chord_idx].chord)); 
		}

		fprintf(fp, "\n"); 
	}
	fprintf(fp, "\n"); 

	return 1; 
}

int song_AddVoice(SONG s, VOICE v)
{
	if (s==NULL) return -1; 
	if (v==NULL) return -1; 
	s->voices[ s->voice_count ] = v; 
	s->voice_count++; 
	return 1; 
}

int song_GetVoiceCount(SONG s)
{
	if (s==NULL) return -1; 
	return s->voice_count; 
}
	
VOICE song_GetVoice(SONG s, int i)
{
	if (s==NULL) return -1; 
	return s->voices[i]; 
}

/* ----------------------------------------------------------------
 * voice definitions
 *
 */

VOICE voice_New(void)
{
	VOICE v=NULL; 
	v = (VOICE)malloc(sizeof(_VOICE)); 
	if ( v==NULL) return NULL; 

	memset(v, 0, sizeof(_VOICE)); 
	return v; 
}
int voice_Delete(VOICE v)
{
	if (v==NULL) return -1; 
	free(v); 
	return 1; 
}


int voice_AddEvent(VOICE v, VOICE_EVENT e, NOTE n)
{
	VOICE_EVENT event=0; 

	if (v==NULL) return -1; 

	//printf("add event...\n"); 

	/* add note */
	if ( e == VOICE_EVENT_NOTE )
	{
		v->notes[ v->notes_count ] = n; 
		event = v->notes_count; 
		v->notes_count++; 
	}
	else
	{
		event = e; 
	}

	/* add event */
	v->events[ v->event_count ] = event; 
	v->event_count++; 

	return 1; 
}

